import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 代码生成器
 *
 * @author hezhao
 * @date 2024-06-27
 */
public class Generator {
    //数据库配置
    public static final String username = "root";
    public static final String password = "root";
    public static final String url = "jdbc:mysql://127.0.0.1:3306/scsx_boot?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai";

    public static void main(String[] args) {
        // 需要生成的表
        final String[] tables = {
                "scsx_user"
        };
        //去掉前缀
        final String prefixArr = "scsx_";
        //项目目录
        String projectDir = "C:\\Users\\hwh\\Desktop\\hu-workspace\\scs";
        //作者
        final String author = "huwenhao";
        //业务层项目名
        final String projectNameBase = "scs_boot";
        //服务包名，默认与projectNameBase 相同
        String servicePackageName = "app";


        //-------------------------------------------下面的基本不用修改-------------------------------------
        projectDir = projectDir + "\\" + projectNameBase;
        //上级包名和目录，这两个选项要一起改
        final String apiPackageName = "com.dmx.scs." + servicePackageName + ".api";
        final String apiParentDir = "/com/dmx/scs/" + servicePackageName + "/api";
        final String bizPackageName = "com.dmx.scs." + servicePackageName;
        final String bizParentDir = "/com/dmx/scs/" + servicePackageName;

        //api
        final String apiPath = projectDir + "/" + projectNameBase + "-api/";
        final String apiBasePath = apiPath + "/src/main/java/" + apiParentDir;
        final String voPath = apiBasePath + "/vo/";
        final String dtoPath = apiBasePath + "/dto/";
        final String entityPath = apiBasePath + "/entity/";

        //biz
        final String bizPath = projectDir + "/" + projectNameBase + "-biz/";
        final String bizBasePath = bizPath + "/src/main/java/" + bizParentDir;
        final String mapperPath = bizBasePath + "/mapper/";
        final String servicePath = bizBasePath + "/service/";
        final String controllerPath = bizBasePath + "/controller/";
        final String mapperXmlPath = bizPath + "/src/main/resources/mapper/";
        final String sqlPath = bizPath + "/src/main/resources/sql/";
        //--------------------------------------------上面是配置，分割线-----------------------------------------------
        // 用来获取Mybatis-Plus.properties文件的配置信息
        AutoGenerator mpg = new AutoGenerator();
        // 1-----------全局配置------------------
        globalConfig(author, mpg);

        // 2----------数据源配置------------------
        dataSourceConfig(mpg);

        // 3-----------表名生成策略配置------------------
        tableGenerator(tables, prefixArr, mpg);

        // 注入自定义配置，可以在 VM 中使用 cfg.abc 【可无】
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>(5);
                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-rb");
                map.put("apiPackageName", apiPackageName);
                map.put("bizPackageName", bizPackageName);
                map.put("prefixLength", prefixArr.length());
                map.put("client_path", projectNameBase);
                map.put("systemTime", System.currentTimeMillis());
                this.setMap(map);

                // 自定义逻辑
                List<TableInfo> tableInfoList = this.getConfig().getTableInfoList();
                for (TableInfo tableInfo : tableInfoList) {
                    String tableName = tableInfo.getName();
                    if (!checkName(tableName)){
                        throw new RuntimeException("表名只能包含小写字母、数字、下划线，不能以下划线开始或结尾，不能有空格和回车,表：" + tableInfo.getName());
                    }
                    String tableComment = tableInfo.getComment();
                    if ( StringUtils.isBlank(tableComment) || tableComment.contains("\n")){
                        throw new RuntimeException("表注释不能为空或者包含换行符,表：" + tableInfo.getName() + " 注释：" + tableComment);
                    }
                    tableInfo.setComment(tableComment.trim());
                    List<TableField> fields = tableInfo.getFields();
                    for (TableField field : fields) {
                        if (!checkName(field.getName())){
                            throw new RuntimeException("字段名只能包含小写字母、数字、下划线，不能以下划线开始或结尾，不能有空格和回车,表：" + tableInfo.getName() + " 字段：" + field.getName());
                        }
                        String fieldComment = field.getComment();
                        if ( StringUtils.isBlank(fieldComment) || fieldComment.contains("\n")){
                            throw new RuntimeException("字段注释不能为空或者包含换行符,表：" + tableInfo.getName() + " 字段：" + field.getName() + " 注释：" + fieldComment);
                        }
                        field.setComment(fieldComment.trim());
                    }
                }
            }
        };

        /**
         * 5----------生成目录配置-------------------
         */
        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();
        List<Object[]> configs = new ArrayList<>();
        //生成文件的配置，模板位置，生成目录，文件后缀
        configs.add(new Object[]{"/templates/entity.java.vm", entityPath, "Do.java"});
        configs.add(new Object[]{"/templates/vo.java.vm", voPath, "Vo.java"});
        configs.add(new Object[]{"/templates/dto.java.vm", dtoPath, "Dto.java"});
        configs.add(new Object[]{"/templates/mapper.java.vm", mapperPath, "Mapper.java"});
        configs.add(new Object[]{"/templates/mapper.xml.vm", mapperXmlPath, "Mapper.xml"});
        configs.add(new Object[]{"/templates/menu.sql.vm", sqlPath, "Menu.sql"});
        configs.add(new Object[]{"/templates/service.java.vm", servicePath + "/impl/", "ServiceImpl.java"});
        configs.add(new Object[]{"/templates/controller.java.vm", controllerPath, "Controller.java"});
        configs.add(new Object[]{"/templates/service.interface.vm", servicePath, "Service.java"});
        //遍历预生成文件
        configs.forEach(config -> {
            focList.add(new FileOutConfig((String) config[0]) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    return config[1] + tableInfo.getEntityName() + config[2];
                }
            });
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 执行生成
        mpg.execute();
    }
    public static boolean checkName(String str) {

        // 检查是否包含空格或回车
        if (str.contains(" ") || str.contains("\n")) {
            return false;
        }

        // 检查是否以下划线开始
        if (str.startsWith("_")) {
            return false;
        }
        // 检查是否以下划线结束
        if (str.endsWith("_")) {
            return false;
        }

        // 检查是否只包含小写字母、数字和下划线
        return str.matches("^[a-z0-9_]+$");
    }
    private static void tableGenerator(String[] tables, String prefixArr, AutoGenerator mpg) {
        StrategyConfig strategy = new StrategyConfig();
        strategy.setTablePrefix(prefixArr);// 生成的实体类不会带前缀"t_"
        strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略 t_user_xxx --->> UserXxx
        strategy.setInclude(tables);
        mpg.setStrategy(strategy);
    }

    private static void dataSourceConfig(AutoGenerator mpg) {
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setTypeConvert(new MySqlTypeConvert());
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername(username);
        dsc.setPassword(password);
        dsc.setUrl(url);
        mpg.setDataSource(dsc);
    }

    private static void globalConfig(String author, AutoGenerator mpg) {
        GlobalConfig gc = new GlobalConfig();
        //        gc.setOutputDir(outputDir);
        gc.setFileOverride(true);
        gc.setActiveRecord(true);// 开启 activeRecord 模式
        gc.setEnableCache(false);// XML 二级缓存
        gc.setBaseResultMap(true);// XML ResultMap
        gc.setBaseColumnList(false);// XML columList
        gc.setAuthor(author);
        gc.setOpen(false);//不打开文件夹
        mpg.setGlobalConfig(gc);
    }
    //查看表结构 AutoGenerator:113
}
